package com.yingxin.yxerp.module.organization.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.taobao.api.ApiException;
import com.yingxin.yx.framework.commons.constant.CommonConst;
import com.yingxin.yx.framework.commons.enums.BusinessType;
import com.yingxin.yx.framework.commons.exception.BizException;
import com.yingxin.yxerp.module.dingtalk.service.IDingDeptBaseService;
import com.yingxin.yxerp.module.dingtalk.service.IWeComDeptBaseService;
import com.yingxin.yxerp.module.dingtalk.vo.DingDeptBaseRespVo;
import com.yingxin.yxerp.module.dingtalk.vo.WeComDeptBaseRespVo;
import com.yingxin.yxerp.module.oplog.aop.OplogAnnotation;
import com.yingxin.yxerp.module.organization.entity.Department;
import com.yingxin.yxerp.module.organization.entity.constant.DeptType;
import com.yingxin.yxerp.module.organization.mapper.DepartmentMapper;
import com.yingxin.yxerp.module.organization.service.IDepartmentMgrService;
import com.yingxin.yxerp.module.organization.service.IDepartmentService;
import com.yingxin.yxerp.module.organization.service.IUserService;
import com.yingxin.yxerp.module.organization.service.helper.DepartmentTreeHelper;
import com.yingxin.yxerp.module.organization.vo.resp.DepartmentRespVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
 * 部门 服务实现类
 * @author fanchao
 * @since 2021-05-13
 */

@Service
public class DepartmentServiceImpl
        extends ServiceImpl<DepartmentMapper, Department>
        implements IDepartmentService {

    @Autowired
    private IDepartmentMgrService departmentMgrService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IDingDeptBaseService dingDeptBaseService;

    @Autowired
    private IWeComDeptBaseService weComDeptBaseService;

    @Override
    public List<Department> listByIds(List<String> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return new ArrayList<>();
        }
        QueryWrapper<Department> qw = new QueryWrapper<>();
        qw.lambda().in(Department::getId, ids);
        return list(qw);
    }

    @Override
    public List<Department> listByParentId(String parentId) {
        QueryWrapper<Department> qw = new QueryWrapper<>();
        qw.lambda().eq(Department::getParentId, parentId);
        return list(qw);
    }

    @Override
    public Department getParentById(String id) {
        QueryWrapper<Department> qw = new QueryWrapper<>();
        qw.lambda().eq(Department::getId, id);
        Department dept = getOne(qw);
        if (dept == null) {
            return null;
        }
        qw = new QueryWrapper<>();
        qw.lambda().eq(Department::getId, dept.getParentId());
        return getOne(qw);
    }

    @OplogAnnotation(biz = BusinessType.DEPT, id = "{{dept.id}}", action = "新增", desc = "部门[{{dept.name}}]，负责人{{dept.deptMgrDesc}}")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void create(Department dept, List<String> managerIds) {
        save(dept);
        updateBatchDeptIds();
        // 保存部门负责人
        departmentMgrService.updateDepartmentMgr(dept, managerIds);
    }

    @OplogAnnotation(biz = BusinessType.DEPT, id = "{{dept.id}}", action = "修改", desc = "部门[{{dept.name}}]，负责人{{dept.deptMgrDesc}}")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void update(Department dept, List<String> managerIds) {
        if (DeptType.HEADQUARTERS.equals(dept.getId())) {
            dept.setParentId(null);
        }
        updateById(dept);
        updateBatchDeptIds();
        // 更新部门负责人
        departmentMgrService.updateDepartmentMgr(dept, managerIds);
    }


    @OplogAnnotation(biz = BusinessType.DEPT, id = "{{dept.id}}", action = "删除", desc = "部门[{{dept.name}}]")
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void delete(Department dept) {
        if (DeptType.HEADQUARTERS.equals(dept.getId())) {
            throw new BizException("无法删除总部");
        }
        List<Department> list = listByParentId(dept.getId());
        if (list.size() > 0) {
            throw new BizException("请先删除下级部门");
        }
        removeById(dept.getId());
    }

    /**
     * 更新直属员工数量
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void updateDirectStaffCountByDeptId(String deptId) {
        Department department = getById(deptId);
        if (department != null) {
            int directStaffCount = userService.countByDeptId(deptId);
            department.setDirectStaffCount(directStaffCount);
            updateById(department);
            updateDirectStaffCountByDeptId(department.getParentId());
        }
    }

    // 更新所有部门直属员工数量
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void updateDirectStaffCount(){
        QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq( Department::getDelFlag, CommonConst.FALSE );
        List<Department> departments = list( queryWrapper );
        for( Department department : departments ){
            updateDirectStaffCountByDeptId( department.getId() );
        }
    }

    @Override
    public void checkLeafDepartment(String id) {
        List<Department> list = listByParentId(id);
        if (list.size() > 0) {
            throw new BizException("只能选择最下级的部门");
        }
    }

    @Override
    public List<DepartmentRespVo> listParentById(String id) {
        if (StringUtils.isNotEmpty(id)) {
            Department dept = getById(id);
            if (dept != null) {
                List<String> list = new ArrayList<>();
                list.add(dept.getId());
                List<String> ids = DepartmentTreeHelper.findParent(list, dept.getParentId(), list());
                return baseMapper.listVoByIds(ids);
            }
        }
        return null;
    }

    /**
     * 更新所有 DeptIds
     */
    private void updateBatchDeptIds() {
        List<Department> departmentList = list();
        for (Department dept : departmentList) {
            List<String> list = new ArrayList<>();
            list.add(dept.getId());
            List<String> ids = DepartmentTreeHelper.findParent(list, dept.getParentId(), departmentList);
            dept.setParentIds(String.join(",", ids));
        }
        updateBatchById(departmentList);
    }

    /**
     * 同步部门档案
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void synchronism() throws ApiException {
        // 获取钉钉部门信息
        List<DingDeptBaseRespVo> dingDeptBaseRespVos = dingDeptBaseService.getDeptBaseList();

        // 循环钉钉部门
        for( DingDeptBaseRespVo dingDeptBaseRespVo : dingDeptBaseRespVos ){
            // 检查是否存在
            Department checkDepartment = getDingDeptById( dingDeptBaseRespVo.getDeptId().toString() );

            // 存在时
            if( ObjectUtil.isNotEmpty( checkDepartment ) ){
                // 不允许同步
                if ( checkDepartment.getIsSynchronism().trim().equals( CommonConst.FALSE ) ){
                    checkDepartment.setName( dingDeptBaseRespVo.getName() );
                    // 更新部门主管
                    if( CollectionUtil.isNotEmpty( dingDeptBaseRespVo.getDeptManagerUseridList() ) ) {
                        departmentMgrService.updateDingDepartmentMgr(checkDepartment, dingDeptBaseRespVo.getDeptManagerUseridList() );
                    }
                }
                // 已经被删除时 - 启用
                if( CommonConst.TRUE.trim().equals( checkDepartment.getDelFlag() ) ){
                    checkDepartment.setDelFlag( CommonConst.FALSE );
                }
                checkDepartment.setSort( dingDeptBaseRespVo.getOrder() );
                // 更新
                updateById( checkDepartment );

                // 更新直属员工数量
                updateDirectStaffCountByDeptId( checkDepartment.getId() );
            }else{
                // 不存在时
                // 获取当前钉钉部门的上级部门
                Department parent = getDingDeptById( dingDeptBaseRespVo.getParentId().toString() );

                String prentId = CommonConst.TRUE;

                // 上级部门存在时
                if( ObjectUtil.isNotEmpty( parent ) ) {
                    prentId = parent.getId();
                }

                Department department = new Department();
                department.setName( dingDeptBaseRespVo.getName() );
                department.setDingDeptId( dingDeptBaseRespVo.getDeptId().toString() );
                department.setParentId( prentId );
                department.setDeptType( CommonConst.THREE );
                department.setSort( dingDeptBaseRespVo.getOrder() );
                department.setCreatorId( CommonConst.TRUE );
                department.setCreateTime( new Date() );
                department.setUpdaterId( CommonConst.TRUE );
                department.setUpdateTime( new Date() );
                department.setDelFlag( CommonConst.FALSE );

                // 保存
                save( department );

                // 更新部门主管
                if( CollectionUtil.isNotEmpty( dingDeptBaseRespVo.getDeptManagerUseridList() ) ) {
                    departmentMgrService.updateDingDepartmentMgr(department, dingDeptBaseRespVo.getDeptManagerUseridList() );
                }

                // 更新直属员工数量
                updateDirectStaffCountByDeptId( department.getId() );
            }
        }

        // 将不再钉钉上的部门排除
        // 所有的钉钉部门ID
        List<Long> dingDeptIds = dingDeptBaseRespVos.stream().map(DingDeptBaseRespVo::getDeptId).collect(Collectors.toList());
        List<String> strDingDeptIds = new ArrayList<>();
        for( Long l : dingDeptIds ){
            strDingDeptIds.add( l.toString() );
        }
        UpdateWrapper<Department> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().notIn( Department::getDingDeptId, strDingDeptIds );
        updateWrapper.lambda().ne( Department::getId, CommonConst.TRUE );
        updateWrapper.lambda().eq( Department::getDelFlag, CommonConst.FALSE );
        updateWrapper.lambda().eq( Department::getIsSynchronism, CommonConst.FALSE );
        updateWrapper.lambda().set( Department::getDelFlag, CommonConst.TRUE );
        update( updateWrapper );

        // 更新所有 DeptIds
        updateBatchDeptIds();
    }

    /**
     * 根据 ding_dept_id 获取部门信息
     */
    @Override
    public Department getDingDeptById(String dingDeptId){
        QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
        // queryWrapper.lambda().eq( Department::getDelFlag, CommonConst.FALSE );
        queryWrapper.lambda().eq( Department::getDingDeptId, dingDeptId );
        List<Department> departments = list( queryWrapper );
        if( departments.size() == 1 ){
            // 仅一个部门时
            return departments.get( 0 );
        }else if ( departments.size() > 1 ){
            // 返回最新的一条
            Department department = departments.get( departments.size() - 1 );
            // 将多余的移除
            for( Department department_ : departments ){
                if( !department.getId().trim().equals( department_.getId().trim() ) ){
                    department_.setDelFlag( CommonConst.TRUE );
                    updateById( department_ );
                }
            }
            return department;
        }else {
            // 无内容
            return null;
        }
    }

    /**
     * 同步部门档案 - 微信企业号
     * @throws ApiException
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void synchronismWeCom(){
        // 获取企业微信部门信息
        List<WeComDeptBaseRespVo> weComDeptBaseRespVos = weComDeptBaseService.getDeptBaseList();

        // 循环钉钉部门
        for( WeComDeptBaseRespVo weComDeptBaseRespVo : weComDeptBaseRespVos ){
            // 检查是否存在
            Department checkDepartment = getWeComDeptById( weComDeptBaseRespVo.getId().toString() );
            // 存在时
            if( ObjectUtil.isNotEmpty( checkDepartment ) ){
                // 不允许同步
                if ( checkDepartment.getIsSynchronism().trim().equals( CommonConst.FALSE ) ){
                    checkDepartment.setName( weComDeptBaseRespVo.getName() );
                    // 更新部门主管
                    //                    if( CollectionUtil.isNotEmpty( weComDeptBaseRespVo.getDepartmentLeader() ) ) {
                    //                        departmentMgrService.updateWeComDepartmentMgr(
                    //                                checkDepartment, weComDeptBaseRespVo.getDepartmentLeader() );
                    //                    }
                }
                // 已经被删除时 - 启用
                if( CommonConst.TRUE.trim().equals( checkDepartment.getDelFlag() ) ){
                    checkDepartment.setDelFlag( CommonConst.FALSE );
                }
                checkDepartment.setSort( weComDeptBaseRespVo.getOrder() );
                // 更新
                updateById( checkDepartment );

                // 更新直属员工数量
                updateDirectStaffCountByDeptId( checkDepartment.getId() );
            }else{
                // 不存在时
                // 获取当前钉钉部门的上级部门
                Department parent = getWeComDeptById( weComDeptBaseRespVo.getParentid().toString() );

                String prentId = CommonConst.TRUE;

                // 上级部门存在时
                if( ObjectUtil.isNotEmpty( parent ) ) {
                    prentId = parent.getId();
                }

                Department department = new Department();
                department.setName( weComDeptBaseRespVo.getName() );
                department.setWeComDeptId( weComDeptBaseRespVo.getId().toString() );
                department.setParentId( prentId );
                department.setDeptType( CommonConst.THREE );
                department.setSort( weComDeptBaseRespVo.getOrder() );
                department.setCreatorId( CommonConst.TRUE );
                department.setCreateTime( new Date() );
                department.setUpdaterId( CommonConst.TRUE );
                department.setUpdateTime( new Date() );
                department.setDelFlag( CommonConst.FALSE );

                // 保存
                save( department );

                // 更新部门主管
                //                if( CollectionUtil.isNotEmpty( weComDeptBaseRespVo.getDepartmentLeader() ) ) {
                //                    departmentMgrService.updateDingDepartmentMgr(department, weComDeptBaseRespVo.getDepartmentLeader() );
                //                }

                // 更新直属员工数量
                updateDirectStaffCountByDeptId( department.getId() );
            }
        }

        // 将不再钉钉上的部门排除
        // 所有的钉钉部门ID
        List<String> dingDeptIds = weComDeptBaseRespVos.stream().map( WeComDeptBaseRespVo::getId ).collect( Collectors.toList() );
        UpdateWrapper<Department> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().notIn( Department::getWeComDeptId, dingDeptIds );
        updateWrapper.lambda().ne( Department::getId, CommonConst.TRUE );
        updateWrapper.lambda().eq( Department::getDelFlag, CommonConst.FALSE );
        updateWrapper.lambda().eq( Department::getIsSynchronism, CommonConst.FALSE );
        updateWrapper.lambda().set( Department::getDelFlag, CommonConst.TRUE );
        update( updateWrapper );

        // 更新所有 DeptIds
        updateBatchDeptIds();
    }

    /**
     * 根据 we_com_dept_id 获取部门信息
     */
    @Override
    public Department getWeComDeptById(String weComDeptId){
        QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
        // queryWrapper.lambda().eq( Department::getDelFlag, CommonConst.FALSE );
        queryWrapper.lambda().eq( Department::getWeComDeptId, weComDeptId );
        List<Department> departments = list( queryWrapper );
        if( departments.size() == 1 ){
            // 仅一个部门时
            return departments.get( 0 );
        }else if ( departments.size() > 1 ){
            // 返回最新的一条
            Department department = departments.get( departments.size() - 1 );
            // 将多余的移除
            for( Department department_ : departments ){
                if( !department.getId().trim().equals( department_.getId().trim() ) ){
                    department_.setDelFlag( CommonConst.TRUE );
                    updateById( department_ );
                }
            }
            return department;
        }else {
            // 无内容
            return null;
        }
    }


    /**
     * 根据 deptIds 获取部门名称
     */
    @Override
    public String getByDeptIds( List<String> deptIds ){
        QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in( Department::getId, deptIds );
        List<Department> departments = list( queryWrapper );
        StringJoiner result = new StringJoiner( "," );
        for( Department department_ : departments ){
            result.add( department_.getName() );
        }
        return result.toString();
    }

}